package com.yunquan.ohana.utils

import android.annotation.SuppressLint
import android.content.Context
import android.location.Address
import android.location.Geocoder
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.annotation.RequiresApi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
import java.util.Locale
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

class LocationHelper(private val context: Context) {

    // 定位回调接口
    interface LocationResultListener {
        fun onLocationSuccess(latitude: Double, longitude: Double, cityName: String?)
        fun onLocationFailed(errorMessage: String)
    }

    private var listener: LocationResultListener? = null
    private var locationManager: LocationManager? = null
    private var locationListener: LocationListener? = null
    private var handler: Handler? = Handler(Looper.getMainLooper())
    private var timeoutRunnable: Runnable? = null

    // 配置参数
    companion object {
        private const val LOG = "LocationHelper"
        private const val LOCATION_TIMEOUT = 15000L // 15秒超时
        private const val MIN_TIME_BETWEEN_UPDATES = 10000L // 10秒更新间隔
        private const val MIN_DISTANCE_CHANGE = 10f // 10米距离变化
        private const val LAST_LOCATION_MAX_AGE = 300000L // 最后位置最大有效期5分钟
    }

    init {
        locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    }

    /**
     * 单次获取位置信息
     */
    fun getSingleLocation(listener: LocationResultListener) {
        this.listener = listener
        // 检查位置服务是否可用
        if (!isLocationEnabled()) {
            listener.onLocationFailed("位置服务未开启，请开启GPS或网络定位")
            return
        }
        // 开始获取位置
        startLocationUpdate()
    }

    /**
     * 检查位置服务是否开启
     */
    fun isLocationEnabled(): Boolean {
        return try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                locationManager?.isLocationEnabled ?: false
            } else {
                @Suppress("Deprecation")
                val gpsEnabled =
                    locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER) ?: false
                val networkEnabled =
                    locationManager?.isProviderEnabled(LocationManager.NETWORK_PROVIDER) ?: false
                gpsEnabled || networkEnabled
            }
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    /**
     * 开始位置更新
     */
    @SuppressLint("MissingPermission")
    private fun startLocationUpdate() {
        // 设置超时
        setupTimeout()
        // 首先尝试获取最后一次已知位置
        val lastLocation = getLastKnownLocation()
        if (lastLocation != null && isLocationFresh(lastLocation)) {
            processLocation(lastLocation)
            return
        }
        // 如果最后位置不可用或太旧，请求新的位置更新
        requestLocationUpdates()
    }

    /**
     * 获取最后一次已知位置
     */
    @SuppressLint("MissingPermission")
    private fun getLastKnownLocation(): Location? {
        return try {
            var bestLocation: Location? = null
            // 尝试从不同 provider 获取最后位置
            val providers = locationManager?.getProviders(true) ?: emptyList()
            for (provider in providers) {
                val location = locationManager?.getLastKnownLocation(provider)
                bestLocation = if (location == null) {
                    null
                } else {
                    if (bestLocation == null ||
                        location.accuracy < bestLocation.accuracy
                    ) {
                        location
                    } else {
                        null
                    }
                }
            }
            bestLocation
        } catch (error: SecurityException) {
            L.e(error.message ?: "")
            error.printStackTrace()
            null
        } catch (error: Exception) {
            L.e(error.message ?: "")
            error.printStackTrace()
            null
        }
    }

    /**
     * 检查位置是否新鲜
     */
    private fun isLocationFresh(location: Location): Boolean {
        val currentTime = System.currentTimeMillis()
        val locationTime = location.time
        return currentTime - locationTime < LAST_LOCATION_MAX_AGE && location.accuracy < 100
    }

    /**
     * 请求位置更新
     */
    @SuppressLint("MissingPermission")
    private fun requestLocationUpdates() {
        locationListener = object : LocationListener {
            override fun onLocationChanged(location: Location) {
                processLocation(location)
                removeLocationUpdates()
            }

            override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
            override fun onProviderEnabled(provider: String) {}
            override fun onProviderDisabled(provider: String) {}
        }
        try {
            // 优先使用网络定位（更快）
            if (locationManager?.isProviderEnabled(LocationManager.NETWORK_PROVIDER) == true) {
                locationManager?.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER,
                    MIN_TIME_BETWEEN_UPDATES,
                    MIN_DISTANCE_CHANGE,
                    locationListener as LocationListener
                )
            }
            // 同时使用GPS定位（更精确）
            if (locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER) == true) {
                locationManager?.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    MIN_TIME_BETWEEN_UPDATES,
                    MIN_DISTANCE_CHANGE,
                    locationListener as LocationListener
                )
            }
        } catch (e: SecurityException) {
            e.printStackTrace()
            listener?.onLocationFailed("定位权限异常")
        } catch (e: Exception) {
            e.printStackTrace()
            listener?.onLocationFailed("定位服务异常: ${e.message}")
        }
    }

    /**
     * 处理获取到的位置
     */
    private fun processLocation(location: Location) {
        cancelTimeout()
        val latitude = location.latitude
        val longitude = location.longitude
        val accuracy = location.accuracy
        // 检查位置精度
        if (accuracy > 500) { // 精度大于500米认为不可用
            listener?.onLocationFailed("定位精度过低: ${accuracy.toInt()}米，请移动到开阔区域")
            return
        }
        // 异步获取城市名称
        getCityNameAsync(latitude, longitude) { cityName ->
            listener?.onLocationSuccess(latitude, longitude, cityName)
        }
    }

    /**
     * 异步获取城市名称
     */
    private fun getCityNameAsync(
        latitude: Double,
        longitude: Double,
        callback: (String?) -> Unit,
    ) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val cityName = getCityNameFromLocation(latitude, longitude)
                withContext(Dispatchers.Main) {
                    callback(cityName)
                }
            } catch (e: Exception) {
                e.printStackTrace()
                withContext(Dispatchers.Main) {
                    callback(null)
                }
            }
        }
    }

    /**
     * 根据经纬度获取城市名称
     */
    private suspend fun getCityNameFromLocation(latitude: Double, longitude: Double): String? {
        return try {
            // 如果系统不提供Geocoder，直接走网络反向地理编码兜底
            if (!Geocoder.isPresent()) return reverseGeocodeByNominatim(latitude, longitude)

            val geocoder = Geocoder(context, getPreferredLocale())

            // 首选Android 13+ 异步API
            val primary: String? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                getCityNameFromLocationAsync(geocoder, latitude, longitude)
            } else {
                // 传统同步API
                getCityNameFromLocationSync(geocoder, latitude, longitude)
            }

            // 如果首选结果为空，尝试同步API作为兜底（即使在Android 13+也尝试一次）
            val fallbackSync: String? = if (primary.isNullOrEmpty()) {
                getCityNameFromLocationSync(geocoder, latitude, longitude)
            } else null

            // 如果仍为空，最后使用开源反向地理编码服务兜底
            primary ?: fallbackSync ?: reverseGeocodeByNominatim(latitude, longitude)
        } catch (e: IOException) {
            e.printStackTrace()
            // 网络异常时，尝试开源反向地理编码兜底
            reverseGeocodeByNominatim(latitude, longitude)
        } catch (e: IllegalArgumentException) {
            e.printStackTrace()
            null // 经纬度无效
        } catch (e: Exception) {
            e.printStackTrace()
            // 其他异常也尝试兜底
            reverseGeocodeByNominatim(latitude, longitude)
        }
    }

    /**
     * Android 13+ 使用最新的异步GeocodeListener API
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    private suspend fun getCityNameFromLocationAsync(
        geocoder: Geocoder,
        latitude: Double,
        longitude: Double,
    ): String? = suspendCoroutine { continuation ->
        val listener = object : Geocoder.GeocodeListener {
            override fun onGeocode(addresses: MutableList<Address>) {
                val cityName = extractCityName(addresses)
                continuation.resume(cityName)
            }

            override fun onError(errorMessage: String?) {
                continuation.resume(null)
            }
        }
        try {
            geocoder.getFromLocation(latitude, longitude, 1, listener)
        } catch (e: Exception) {
            e.printStackTrace()
            continuation.resume(null)
        }
    }

    /**
     * Android 13- 使用传统同步API
     */
    @Suppress("Deprecation")
    private fun getCityNameFromLocationSync(
        geocoder: Geocoder,
        latitude: Double,
        longitude: Double,
    ): String? {
        return try {
            val addresses = geocoder.getFromLocation(latitude, longitude, 1)
            extractCityName(addresses)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    /**
     * 从Address列表中提取城市名称
     */
    private fun extractCityName(addresses: List<Address>?): String? {
        return addresses?.firstOrNull()?.let { address ->
            // 优先级: 城市 -> 区/县(subAdminArea) -> 街道(thoroughfare) -> 区县 -> 省份 -> 国家
            address.locality
                ?: address.subAdminArea
                ?: address.thoroughfare
                ?: address.subLocality
                ?: address.adminArea
                ?: address.countryName
        }
    }

    /**
     * 使用开源的Nominatim(OpenStreetMap)服务进行反向地理编码兜底。
     * 注意：该服务有速率限制，建议仅在系统Geocoder不可用时使用。
     */
    private fun reverseGeocodeByNominatim(latitude: Double, longitude: Double): String? {
        return try {
            val locale = getPreferredLocale()
            val languageTag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                locale.toLanguageTag()
            } else {
                // 兼容低版本，构造如 zh-CN / en-US
                if (locale.country.isNullOrEmpty()) locale.language else locale.language + "-" + locale.country
            }

            val url = java.net.URL(
                "https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=" +
                        latitude + "&lon=" + longitude + "&zoom=10&addressdetails=1&accept-language=" +
                        java.net.URLEncoder.encode(languageTag, "UTF-8")
            )
            val conn = url.openConnection() as java.net.HttpURLConnection
            conn.requestMethod = "GET"
            conn.setRequestProperty("User-Agent", "ohana-app/1.0 (android)")
            conn.setRequestProperty("Accept-Language", languageTag)
            conn.connectTimeout = 5000
            conn.readTimeout = 5000

            val code = conn.responseCode
            if (code != 200) {
                conn.disconnect()
                return null
            }

            val inputStream = conn.inputStream
            val response = inputStream.bufferedReader().use { it.readText() }
            conn.disconnect()

            // 简单解析JSON，提取城市相关字段
            val json = org.json.JSONObject(response)
            val address = json.optJSONObject("address")
            if (address != null) {
                val city = address.optString("city", null)
                val town = address.optString("town", null)
                val village = address.optString("village", null)
                val county = address.optString("county", null)
                val state = address.optString("state", null)
                val country = address.optString("country", null)
                return city ?: town ?: village ?: county ?: state ?: country
            }
            null
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    /**
     * 获取当前应用的首选Locale（支持App语言设置）。
     */
    private fun getPreferredLocale(): Locale {
        return Locale.getDefault()
    }

    /**
     * 设置超时检查
     */
    private fun setupTimeout() {
        timeoutRunnable = Runnable {
            onLocationTimeout()
        }
        handler?.postDelayed(timeoutRunnable!!, LOCATION_TIMEOUT)
    }

    /**
     * 定位超时处理
     */
    private fun onLocationTimeout() {
        removeLocationUpdates()
        listener?.onLocationFailed("定位超时，请检查网络连接或GPS信号，并确保位置服务已开启")
    }

    /**
     * 取消超时检查
     */
    private fun cancelTimeout() {
        timeoutRunnable?.let {
            handler?.removeCallbacks(it)
        }
        timeoutRunnable = null
    }

    /**
     * 移除位置更新监听
     */
    private fun removeLocationUpdates() {
        cancelTimeout()
        locationListener?.let {
            locationManager?.removeUpdates(it)
        }
        locationListener = null
    }

    /**
     * 清理资源
     */
    fun destroy() {
        removeLocationUpdates()
        handler?.removeCallbacksAndMessages(null)
        handler = null
        listener = null
        locationManager = null
    }

    /**
     * 获取可用的定位提供商
     */
    fun getAvailableProviders(): List<String> {
        return try {
            locationManager?.getProviders(true)?.toList() ?: emptyList()
        } catch (e: Exception) {
            e.printStackTrace()
            emptyList()
        }
    }

    /**
     * 检查是否支持GPS定位
     */
    fun hasGpsProvider(): Boolean {
        return locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER) ?: false
    }

    /**
     * 检查是否支持网络定位
     */
    fun hasNetworkProvider(): Boolean {
        return locationManager?.isProviderEnabled(LocationManager.NETWORK_PROVIDER) ?: false
    }
}